using DG.Tweening;
using System;
using System.Collections.Generic;
using UnityEngine;
using Yoozoo.Core.Extensions.CSharp;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using Yoozoo.Mars.Got;

namespace Yoozoo.Gameplay.City
{
    [HelpURL("https://youzu.feishu.cn/docx/doxcnqz0O1BmiPzdLNTkm137geb")]
    public class City4xFogComponent : MonoBehaviour
    {
        public int width = 90;
        public int height = 90;
        public int edge = 2;

        public float fogHeight = 4f;

        public int WidthEdge => width + edge + edge;
        public int HeightEdge => height + edge + edge;

        [Header("格子大小")]
        public Vector3 cityCellSize = new Vector3(0.015625f, 0.08f, 0.015625f);
        [Header("旋转角")]
        public float gridViewAngleY = 45;

        public string maskTexPath = "/ResourcesAssets/City/Texture/";
        //public string maskTxtPath = "/ResourcesAssets/City/Config/";
        //public List<Texture2D> maskTextures;
        public List<string> maskTexturePaths;
        public List<GameObject> fogPlans = new List<GameObject>();
        public string texPropName = "_InfoTex";
        public MeshRenderer meshRenderer;
        private Material _material;
        private CityAreaConfig _areaConfig;
        public Texture2D fogMaskTex;

        public GameObject disperseFogMesh;
        public int disperseEdge = 1;

        private float _disperseAlpha = 0;
        [Header("迷雾消散的速度")]
        public float disperseSpeed = 5f;

        public float fogEffectTime = 1.5f;
        
        private static Color disperseColor = new Color(1.0f, 0, 0);
        private static Color unlockColor = new Color(0, 0, 0);
        private static Color fogColor = new Color(1, 1, 0);

        public byte[,] fogArray;

        private ResLoader _maskLoader;

        [Header("外围迷雾")]
        public GameObject FogOutRoot;

        [Header("各个区域对应的外围迷雾掩码列表")]
        public int[] FogOutAreaMasks;

        private Material fogOutMaterial;

        public int AreaCount => _areaConfig?.citySubAreas?.Count ?? 0;

        private void Awake()
        {
            transform.localPosition = new Vector3(0, fogHeight, 0);
        }

        public void Init(TextAsset _areaAsset)
        {
            _areaConfig = JsonUtility.FromJson<CityAreaConfig>(_areaAsset.text);
            _areaConfig.InitMap();

            width = _areaConfig.width;
            height = _areaConfig.height;
            fogArray = new byte[WidthEdge, HeightEdge];

            if (meshRenderer)
            {
                _material = meshRenderer.sharedMaterial;
                _material.SetVector("_UVScaleXY", new Vector4(WidthEdge, HeightEdge, 0, 0));

                // meshRenderer.transform.rotation = Quaternion.Euler(0, gridViewAngleY - 180, 0);
            }
        }

        public void Dispose()
        {
            _maskLoader?.Recycle2Cache();
            _maskLoader = null;

            if (fogMaskTex)
            {
                //现在是读取资源，不删除
                //GameObject.DestroyImmediate(fogMaskTex);
                fogMaskTex = null;
            }
        }

        public void BuildBeginMask()
        {
            fogMaskTex = new Texture2D(WidthEdge, HeightEdge, TextureFormat.RG16, false, false);
            fogMaskTex.filterMode = FilterMode.Point;
            for (int i = 0; i < WidthEdge; i++)
            {
                for (int j = 0; j < HeightEdge; j++)
                {
                    fogMaskTex.SetPixel(i, j, fogColor);
                }
            }

            for (int i = 0; i < edge; i++)
            {
                // (1, 0]
                float alpha = ((float)edge - i - 1) / edge;

                // (1, 0.5]
                //alpha = (1 + alpha) * 0.5f;
                for (int j = 0; j < HeightEdge; j++)
                {
                    fogMaskTex.SetPixel(i + width + edge, j, fogColor * alpha);
                }
            }

            fogMaskTex.Apply();
        }

        private int[] _lastDisperseGridIndex;
        private void ClearLastDisperseValue()
        {
            if (_lastDisperseGridIndex != null)   // 清散上一次消散的迷雾的G通道数据
            {
                foreach (var lgi in _lastDisperseGridIndex)
                {
                    Index2Grid(lgi, out var x, out var y);
                    fogMaskTex.SetPixel(x, y, unlockColor);
                }
                _lastDisperseGridIndex = null;
            }
        }

        /// <summary>
        /// 解锁边缘
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="color"></param>
        public void UnlockEdge(int x, int y, Color color)
        {
            // 处理4个边
            if (x == edge)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(i, y, Color.Lerp(fogColor, color, (float)(i - 1) / edge));
            }
            else if (x == width + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(i + width + edge, y, color);
            }

            if (y == edge)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(x, i, Color.Lerp(fogColor, color, (float)(i - 1) / edge));
            }
            else if (y == height + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(x, i + height + edge, Color.Lerp(color, fogColor, (float)(i + 2) / edge));
            }

            // 处理4个角
            if (x == edge && y == edge)
            {
                for (int i = 0; i < edge; i++)
                for (int j = 0; j < edge; j++)
                    //fogMaskTex.SetPixel(i, j, Color.Lerp(fogColor, color, (float)(i + j - 2) / edge / 2));
                    fogMaskTex.SetPixel(i, j, Color.Lerp(fogColor, color, (float)(i - 1) * (j - 1) / edge / edge / 2));
            }
            else if (x == width + edge - 1 && y == edge)
            {
                for (int i = 0; i < edge; i++)
                    for (int j = 0; j < edge; j++)
                        //fogMaskTex.SetPixel(i + width + edge, j, Color.Lerp(fogColor, color, (float)(j - 1) / edge));
                        fogMaskTex.SetPixel(i + width + edge, j, color);
            }
            else if (x == edge && y == height + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                for (int j = 0; j < edge; j++)
                    //fogMaskTex.SetPixel(i, j + height + edge, Color.Lerp(fogColor, color, (float)(i + edge - j - 3) / edge / 2));
                    fogMaskTex.SetPixel(i, j + height + edge,
                        Color.Lerp(fogColor, color, (float)(i - 1) * (edge - j - 1) / edge / edge / 2));
            }
            else if (x == width + edge - 1 && y == height + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    for (int j = 0; j < edge; j++)
                        //fogMaskTex.SetPixel(i + width + edge, j + height + edge, Color.Lerp(color, fogColor, (float)(j + 2) / edge));
                        fogMaskTex.SetPixel(i + width + edge, j + height + edge, color);
            }
        }

        /// <summary>
        /// 编辑器下解锁边缘, 边缘部分直接留白
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="color"></param>
        private void UnlockEdgeEditor(int x, int y, Color color)
        {
            // 处理4个边
            if (x == edge)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(i, y, color);
            }
            else if (x == width + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(i + width + edge, y, color);
            }

            if (y == edge)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(x, i, color);
            }
            else if (y == height + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    fogMaskTex.SetPixel(x, i + height + edge, color);
            }

            // 处理4个角
            if (x == edge && y == edge)
            {
                for (int i = 0; i < edge; i++)
                    for (int j = 0; j < edge; j++)
                        fogMaskTex.SetPixel(i, j, color);
            }
            else if (x == width + edge - 1 && y == edge)
            {
                for (int i = 0; i < edge; i++)
                    for (int j = 0; j < edge; j++)
                        fogMaskTex.SetPixel(i + width + edge, j, color);
            }
            else if (x == edge && y == height + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    for (int j = 0; j < edge; j++)
                        fogMaskTex.SetPixel(i, j + height + edge, color);
            }
            else if (x == width + edge - 1 && y == height + edge - 1)
            {
                for (int i = 0; i < edge; i++)
                    for (int j = 0; j < edge; j++)
                        fogMaskTex.SetPixel(i + width + edge, j + height + edge, color);
            }
        }

        // 解锁不同区域的格子
        public void UnlockFogGrids(int[] gridIndex, bool disperse)
        {
            if (gridIndex.Length == 0)
            {
                return;
            }

            _disperseAlpha = 0;
            ClearLastDisperseValue();
            var tweener = DOVirtual.Float(1f, 0f, disperseSpeed, 
                alpha => { _material.SetFloat("_FogValue", alpha); });
            tweener.onComplete = () =>
            {
                _material.SetFloat("_FogValue", _disperseAlpha);
                _lastDisperseGridIndex = gridIndex;

                var color = disperse ? disperseColor : unlockColor;
                foreach (var gi in gridIndex)
                {
                    // 将需要消散的迷雾数据写入g通道，
                    Index2Grid(gi, out var x, out var y);
                    fogMaskTex.SetPixel(x, y, color);
                    UnlockEdge(x, y, color);
                }

                fogMaskTex.Apply();
                if (disperse)
                {
                    Timers.inst.Remove(SetDisperseAlpha);
                    Timers.inst.AddUpdate(SetDisperseAlpha);
                }
            };
            
        }

        private void SetDisperseAlpha(object o)
        {
            _disperseAlpha += Time.deltaTime * disperseSpeed;
            if (_disperseAlpha > 1)
            {
                _disperseAlpha = 1;
                Timers.inst.Remove(SetDisperseAlpha);
                ClearLastDisperseValue();
            }
            _material.SetFloat("_FogValue", _disperseAlpha);
        }

        public void UnlockAreaFogByTex(int areaId, bool effect = false ,Action callback = null)
        {
            ClearLastDisperseValue();

            if (_maskLoader == null) 
                _maskLoader = ResLoader.Alloc();

            _maskLoader.Add2LoadRapid(maskTexturePaths[areaId], (success, assetName, asset) =>
            {
                if (success && asset is Texture2D maskTex)
                {
                    fogMaskTex = maskTex;
                    _material.SetFloat("_FogValue", 0);
                    _material.SetTexture(texPropName, fogMaskTex);

                    UnlockFogOut(areaId);

                    if (effect)
                    {
                        var tweener = DOVirtual.Float(0, 1f, fogEffectTime, 
                            alpha => { _material.SetFloat("_FogValue", alpha); });
                        tweener.onComplete = () =>
                        {
                            callback?.Invoke();
                        };
                    }
                    else
                    {
                        _material.SetFloat("_FogValue", 1);
                        callback?.Invoke();
                    }
                }
            });
            _maskLoader.Load();
        }

        /// <summary>
        /// 解锁外围雾
        /// </summary>
        /// <param name="areaId"></param>
        public void UnlockFogOut(int areaId)
        {
            if (fogOutMaterial)
            {
                // 已初始化过，这里是播放解锁效果
                FadeFogOut(areaId);
            }
            else
            {
                // 未初始化，这里不播放解锁效果，直接设置
                InitFogOut(areaId);
            }
        }
        
        public void PreShowEvent(int state)
        {
            if (_material)
            {
                _material.SetInt("_OpenWaitLock", state);
                // 红光让强制设置
                if (state == 1)
                {
                    _material.EnableKeyword("_OPENWAITLOCK_ON");
                    
                }
                else
                {
                    _material.DisableKeyword("_OPENWAITLOCK_ON");
                }
            }
        }

        private void FadeFogOut(int areaId)
        {
            if (areaId >= FogOutAreaMasks.Length) return;
            
            for (int i = 0; i < fogPlans.Count; i++)
            {
                if ((i + 1) != areaId)
                {
                    fogPlans[i].SetActive(false);
                }
                else
                {
                    fogPlans[i].SetActive(true);
                }
            }
            
            fogOutMaterial.SetFloat("_StateValue", FogOutAreaMasks[areaId - 1]);
            fogOutMaterial.SetFloat("_StateValueIng", FogOutAreaMasks[areaId]);
            fogOutMaterial.SetFloat("_OutBlendValue", 0);
            var tweener = DOVirtual.Float(0f, 1f, fogEffectTime, 
                alpha => { fogOutMaterial.SetFloat("_OutBlendValue", alpha); });
            tweener.onComplete = () =>
            {
                fogOutMaterial.SetFloat("_StateValue", FogOutAreaMasks[areaId]);
                fogOutMaterial.SetFloat("_StateValueIng", FogOutAreaMasks[areaId]);
                fogOutMaterial.SetFloat("_OutBlendValue", 1);
            };
        }

        private void InitFogOut(int areaId)
        {
            if (FogOutRoot == null)
                return;

            var fogOutRenderer = FogOutRoot.GetComponent<MeshRenderer>();
            if (fogOutRenderer == null)
                return;

            var material = fogOutRenderer.sharedMaterial;
            
            for (int i = 0; i < fogPlans.Count; i++)
            {
                if ((i + 1) != areaId)
                {
                    fogPlans[i].SetActive(false);
                }else
                {
                    fogPlans[i].SetActive(true);
                    material = fogPlans[i].GetComponent<MeshRenderer>().sharedMaterial;
                }
            }
            
            if (material == null)
                return;

            fogOutMaterial = material;

            float value = FogOutAreaMasks[areaId];
            fogOutMaterial.SetFloat("_StateValue", value);
            fogOutMaterial.SetFloat("_StateValueIng", value);
            fogOutMaterial.SetFloat("_OutBlendValue", 1f);
        }

        /// <summary>
        /// 编辑器下测试雾的解锁
        /// </summary>
        /// <param name="areaId"></param>
        public void UnlockAreaFogEditor(int areaId)
        {
            UnlockAreaFog(areaId);
            UnlockFogOut(areaId);
        }

        // EDITOR 解锁区域迷雾
        public void UnlockAreaFog(int areaId)
        {
            int originAreaId = areaId;
            
            if (originAreaId > 1)
            {
                areaId--;
            }
            
            // 1.去除当前区域像素值
            var area = _areaConfig.GetArea(areaId);
            if (area != null)
            {
                foreach (var areaRect in area.grids)
                {
                    int minX = areaRect.x;
                    int maxX = areaRect.x + areaRect.width;
                    int minY = areaRect.y;
                    int maxY = areaRect.y + areaRect.height;

                    for (int x = minX; x <= maxX; x++)
                    {
                        for (int y = minY; y <= maxY; y++)
                        {
                            int xe = x + edge;
                            int ye = y + edge;
                            fogMaskTex.SetPixel(xe, ye, unlockColor);
                            UnlockEdgeEditor(xe, ye, unlockColor);
                        }
                    }
                }
            }

            // 2.去除下一区域g通道值
            if (originAreaId > 1)
            {
                var nextArea = _areaConfig.GetArea(areaId + 1);
                if (nextArea != null)
                {
                    foreach (var areaRect in nextArea.grids)
                    {
                        int minX = areaRect.x;
                        int maxX = areaRect.x + areaRect.width;
                        int minY = areaRect.y;
                        int maxY = areaRect.y + areaRect.height;

                        for (int x = minX; x <= maxX; x++)
                        {
                            for (int y = minY; y <= maxY; y++)
                            {
                                int xe = x + edge;
                                int ye = y + edge;
                                fogMaskTex.SetPixel(xe, ye, disperseColor);
                                UnlockEdgeEditor(xe, ye, disperseColor);
                            }
                        }
                    }
                }
            }

            fogMaskTex.Apply();
        }

        public void SetWaitLockTexOffset(float offsetX, float offsetY)
        {
            _material.SetTextureOffset("_WaitLockTex", new Vector2(offsetX, offsetY));
        }

        private void Index2Grid(int index, out int x, out int y)
        {
            x = index % width + edge;
            y = index / height + edge;
        }

        private int Grid2Index(int x, int y)
        {
            return (y - edge) * height + x - edge;
        }

        private bool IsValidGird(int x, int y)
        {
            return x >= 0 && x < WidthEdge && y >= 0 && y < HeightEdge;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="grid"> 左下角坐标 </param>
        /// <param name="size"></param>
        /// <returns></returns>
        private Vector3 Grid2DispersePos(Vector2Int grid, Vector2Int size)
        {
            Vector3 pos = Vector3.zero;
            Vector3 bottomLeft = new Vector3(-WidthEdge * cityCellSize.x * 0.5f, 0, -HeightEdge * cityCellSize.z * 0.5f);

            pos.x = grid.x * cityCellSize.x + bottomLeft.x;
            pos.z = grid.y * cityCellSize.z + bottomLeft.z;

            pos.x += size.x * cityCellSize.x * 0.5f;
            pos.z += size.y * cityCellSize.z * 0.5f;

            float cityViewRad = Mathf.PI * gridViewAngleY / 180.0f;
            float cosCityViewRad = Mathf.Cos(cityViewRad);
            float sinCityViewRad = Mathf.Sin(cityViewRad);

            float ox = pos.x;
            float oz = pos.z;

            pos.x = cosCityViewRad * ox + sinCityViewRad * oz;
            pos.z = -sinCityViewRad * ox + cosCityViewRad * oz;

            return pos;
        }

        private float GetLockFogValue(int x, int y)
        {
            int v = 0;


            bool isEdgeTop = false;
            bool isEdgeLeft = false;
            bool isEdgeBottom = false;
            bool isEdgeRight = false;

            if (IsValidGird(x, y + 1) && fogArray[x, y + 1] == 1)
            {
                // 上面解锁，上面有边
                v |= 16;
                isEdgeTop = true;
            }

            if (IsValidGird(x - 1, y) && fogArray[x - 1, y] == 1)
            {
                // 左边解锁，左侧有边
                v |= 32;
                isEdgeLeft = true;
            }

            if (IsValidGird(x, y - 1) && fogArray[x, y - 1] == 1)
            {
                // 下面解锁，下面有边
                v |= 64;
                isEdgeBottom = true;
            }

            if (IsValidGird(x + 1, y) && fogArray[x + 1, y] == 1)
            {
                // 右边解锁，右侧有边
                v |= 128;
                isEdgeRight = true;
            }


            if (IsValidGird(x - 1, y + 1) && (fogArray[x - 1, y + 1] == 1) && (!isEdgeLeft) && (!isEdgeTop))
            {
                // 左上角有一个朝内的角，条件：左上解锁，且左侧和上侧无边。
                v |= 1;
            }

            if (IsValidGird(x - 1, y - 1) && (fogArray[x - 1, y - 1] == 1) && (!isEdgeLeft) && (!isEdgeBottom))
            {
                // 左下角有一个朝内的角，条件：左下解锁，且左侧和下侧无边。
                v |= 2;
            }

            if (IsValidGird(x + 1, y - 1) && (fogArray[x + 1, y - 1] == 1) && (!isEdgeRight) && (!isEdgeBottom))
            {
                // 右下角有一个朝内的角，条件：右下解锁，且右侧和下侧无边。
                v |= 4;
            }

            if (IsValidGird(x + 1, y + 1) && (fogArray[x + 1, y + 1] == 1) && (!isEdgeRight) && (!isEdgeTop))
            {
                // 右上角有一个朝内的角，条件：右上解锁，且右侧和上侧无边。
                v |= 8;
            }

            if (v > 0.1)
            {
                return v * 1.0f / 255;
            }

            return 0;
        }

        /// <summary>
        /// 外围迷雾挖洞
        /// </summary>
        public void DigHoleFogOut(int holeIndex, bool enable)
        {
            if (fogOutMaterial == null)
                return;

            string keyword = null;

            if (holeIndex == 1)
            {
                keyword = "_OPENWAITLOCK_ON";
            }
            else if (holeIndex == 2)
            {
                keyword = "_OPENWAITLOCKTWO_ON";
            }
            else if (holeIndex == 3)
            {
                keyword = "_OPENWAITLOCKTHREE_ON";
            }

            if (string.IsNullOrEmpty(keyword))
                return;

            if (enable)
            {
                fogOutMaterial.EnableKeyword(keyword);
            }
            else
            {
                fogOutMaterial.DisableKeyword(keyword);
            }
        }

    }
}
